type EVENT_BUS_E_VAL<P, K extends keyof P> = {
    suffix: string | -1
    func: EVENT_FUNC<P[K]>[]
}
type EVENT_BUS_E<P> = {
    [K in keyof P]?: EVENT_BUS_E_VAL<P, K>[]
}
type FUNC_PARAM<T> = {
    [k in keyof T]: T[k]
}
interface EVENT_FUNC<T> {
    (param: T): void
}
export class EventBusClass<P extends Object>{
    private e: EVENT_BUS_E<P> = {}
    private execFuncType(val?: { suffix?: string, matchAll?: boolean }) {
        if (val) {
            if (val.matchAll) return 'matclAll'
            else if (val.suffix) return 'suffix'
            else return 'default'
        } else {
            return 'default'
        }
    }
    $on<K extends keyof P>(name: K, exec: EVENT_FUNC<P[K]>, suffix?: string) {
        if (this.e[name] == undefined || this.e[name] == null) {
            this.e[name] = []
        }
        if (suffix) {
            let find = this.e[name]?.find(_ => _.suffix === suffix)
            if (find) {
                find.func.push(exec)
            } else {
                this.e[name]?.push({
                    suffix: suffix,
                    func: [exec]
                })
            }
        } else {
            let find = this.e[name]?.find(_ => _.suffix === -1)
            find ? find.func.push(exec) : this.e[name]?.push({
                suffix: -1,
                func: [exec]
            })
        }
    }
    $off<K extends keyof P>(name: K, suffix?: string | -1) {
        if (suffix != undefined) {
            if (this.e[name]) {
                let i = this.e[name]?.findIndex(_ => _.suffix === suffix)
                i = i === undefined ? -1 : i
                i > -1 ? this.e[name]?.splice(i, 1) : null
            }
        } else {
            if (this.e[name]) delete this.e[name]
        }
    }
    $emit<N extends keyof P>(name: N, param: P[N], val?: { suffix?: string, matchAll?: boolean }) {
        let eObj = this.e[name]
        if (eObj == undefined) return false
        switch (this.execFuncType(val)) {
            case 'matclAll':
                eObj.forEach(_ => {
                    _.func.forEach(__ => {
                        __(param)
                    })
                })
                break;
            case 'suffix':
                let _suffix = eObj.find(_ => _.suffix === val?.suffix)
                _suffix?.func.forEach(f => f(param))
                break;
            case 'default':
                let _default = eObj.find(_ => _.suffix === -1)
                _default?.func.forEach(f => f(param))
                break;
            default:
                break;
        }
    }
    $offAll() {
        this.e = {}
    }
}